package com.lx.base;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.LambdaUtils;
import com.baomidou.mybatisplus.core.toolkit.support.ColumnCache;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lx.base.api.dto.BaseDto;
import com.lx.base.api.param.BaseParam;
import com.lx.base.api.param.PageBaseParam;
import com.lx.base.util.BaseBeanUtills;
import com.lx.base.util.PageUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.List;
import java.util.Map;

/**
 * @author lixing
 * @date 2022/7/25 17:23
 */
public  class BaseServiceImpl<M extends BaseMapper<T>,T extends BaseEntity,DTO,ADD,UPDATE extends BaseParam,PAGEPARAM extends PageBaseParam> extends ServiceImpl<M,T>  implements BaseService<T,DTO,ADD,UPDATE,PAGEPARAM> {
    @Override
    public BaseDto<DTO> findById(java.io.Serializable id) {
        T t = super.getById(id);
        return BaseDto.success(t2DTO(t));
    }


    @Override
    public BaseDto<DTO> add(ADD add) throws Exception {
        T object = (T) newInstanceByType("T");
        BeanUtils.copyProperties(add, object);
        this.baseMapper.insert(object);
        return BaseDto.success(t2DTO(object));
    }

    @Override
    public BaseDto updateByParam(UPDATE updateParam) throws Exception {
        T object = (T) newInstanceByType("T");
        BeanUtils.copyProperties(updateParam, object);
        LambdaUpdateChainWrapper<T> updateChainWrapper = super.lambdaUpdate();
        updateChainWrapper.eq(T::getId, object.getId());
        object2LambdaUpdateChainWrapper(object, updateChainWrapper);
        updateChainWrapper.update();
        return BaseDto.success();
    }

    @Override
    public BaseDto<List<DTO>> pagelist(PAGEPARAM pageparam) throws Exception {
        LambdaQueryChainWrapper<T> queryWrapper = super.lambdaQuery();
        pageBaseParam2LambdaQueryChainWrapper(pageparam, queryWrapper);
        Page<T> tpage = PageUtils.getPage(pageparam.getPagination());
        tpage = queryWrapper.page(tpage);
        return BaseDto.success(tpage, getActualTypeArgumentsClass("DTO"));
    }
    @Override
    public List<T> pagelist2T(PAGEPARAM pageparam) throws Exception {
        LambdaQueryChainWrapper<T> queryWrapper = super.lambdaQuery();
        pageBaseParam2LambdaQueryChainWrapper(pageparam, queryWrapper);
        Page<T> tpage = PageUtils.getPage(pageparam.getPagination());
        tpage = queryWrapper.page(tpage);
       return tpage.getRecords();
    }

    @Override
    public DTO t2DTO(T t) {
        DTO object = null;
        try {
            object=  (DTO)BaseBeanUtills.copyProperties(t, getActualTypeArgumentsClass("DTO"));
        } catch (Exception illegalAccessException) {
            log.error("数据转化异常");
            log.error(illegalAccessException.getMessage());
            return null;
        }
        return  object;
    }

    protected void pageBaseParam2LambdaQueryChainWrapper(PAGEPARAM pageBaseParam, LambdaQueryChainWrapper<T> queryWrapper) {
    }

    /***
     * 反射获取实例类
     *
     * @param cla
     * @return
     */
    private Class getActualTypeArgumentsClass(String cla) {
        switch (cla) {
            case "DTO":
                return (Class<DTO>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[2];
            case "T":
                return (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[1];
        }
        return null;
    }

    private Object newInstanceByType(String cla) {
        Class tClass = getActualTypeArgumentsClass(cla);
        try {
            return tClass.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }

    private void object2LambdaUpdateChainWrapper(Object object, LambdaUpdateChainWrapper updateChainWrapper) {
        Class<?> clazz = object.getClass();
        Field[] fields = clazz.getDeclaredFields();
        Map<String, ColumnCache> columnCacheMap = LambdaUtils.getColumnMap(clazz);
        String column = null;
        for (Field f : fields) {
            f.setAccessible(true);
            Object value = null;
            try {
                value = f.get(object);
                column = columnCacheMap.get(f.getName()).getColumn();
                if (value != null && !StringUtils.isEmpty(column)) {
                    updateChainWrapper.set(column, value);
                }
            } catch (IllegalAccessException e) {
                log.error("更新出错", e);

            }
        }
    }


}